package com.learn.question;

import com.google.common.util.concurrent.*;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.*;
import java.util.concurrent.locks.LockSupport;

/**
 * @author wangxing
 * @version 2020/8/4 15:59 Administrator
 */
public class Temp20200804 {
    //    初始化字符串数组
    String[] str1 = new String[26];
    String[] str2 = new String[26];

    {
        for (int i = 0; i < 26; i++) {
            str1[i] = String.valueOf((i + 1));
            str2[i] = String.valueOf((char) ('A' + i));
        }
    }

    //    定义使用的两个线程
    static Thread t1, t2 = null;

    /**
     * 多线程拼接字符串
     * 使用两个线程将1到26和A到Z依次拼接到一起
     * 核心问题是线程间的通讯,只要线程间能相互通讯进行通知即可完成这个问题
     * 线程通讯的方式
     * 实现使用了
     * 1.锁机制
     * 2.自旋锁的实现
     * 3.阻塞队列的实现
     * 4.管道流的实现
     * 5.使用synchronized和wait,notify实现
     * @param args
     */


    public static void main(String[] args) throws IOException, InterruptedException {
        Temp20200804 temp = new Temp20200804();
//        temp.getMultiThreadStringArrJoin_LockSupport();
//        temp.getMultiThreadStringArrJoin_SpinLock();
//        temp.getMultiThreadStringArrJoin_BlockingQueue();
//        temp.getMultiThreadStringArrJoin_Piped();
//        temp.getMultiThreadStringArrJoin_WaitNotify();
        temp.multiThread();
    }

    /**
     * 多线程拼接字符串
     * 使用两个线程将1到26和A到Z依次拼接到一起
     * 本例子使用LockSupport实现
     */
    public void getMultiThreadStringArrJoin_LockSupport() {
        t1 = new Thread(() -> {
            for (String s : str1) {
                System.out.print(s);
//                启动t2线程
                LockSupport.unpark(t2);
//                暂停当前线程
                LockSupport.park();
            }
            System.out.println();
        }, "t1");
        t2 = new Thread(() -> {
            for (String s : str2) {
//                暂停当前线程
                LockSupport.park();
                System.out.print(s);
//                启动t1线程
                LockSupport.unpark(t1);
            }
            System.out.println();
        });
        t1.start();
        t2.start();

    }

    enum ReadToRun {T1, T2}

    ;
    /**
     * volatile为了能更新后立刻从内存中得到
     */
    static volatile ReadToRun r = ReadToRun.T1;

    /**
     * 多线程拼接字符串
     * 使用两个线程将1到26和A到Z依次拼接到一起
     * 自旋实现
     */
    public void getMultiThreadStringArrJoin_SpinLock() {
        new Thread(() -> {
            for (String s : str1) {
                while (r != ReadToRun.T1) {
                }
                System.out.print(s);
                r = ReadToRun.T2;
            }
            System.out.println();
        }).start();
        new Thread(() -> {
            for (String s : str2) {
                while (r != ReadToRun.T2) {
                }
                System.out.print(s);
                r = ReadToRun.T1;
            }
            System.out.println();
        }).start();
    }

    static BlockingQueue<String> q1 = new ArrayBlockingQueue<>(1);
    static BlockingQueue<String> q2 = new ArrayBlockingQueue<>(1);

    /**
     * 多线程拼接字符串
     * 使用两个线程将1到26和A到Z依次拼接到一起
     * 阻塞队列实现
     */
    public void getMultiThreadStringArrJoin_BlockingQueue() {
        new Thread(() -> {
            for (String s : str1) {
                System.out.print(s);
                try {
//                    向q1中放入一个内容
                    q1.put("1");
//                    阻塞q2,如果q2中有内容就直接取出,q2中没有内容就阻塞
                    q2.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println();
        }).start();
        new Thread(() -> {
            for (String s : str2) {
                try {
//                    取出q1中的内容,如果没有就阻塞
                    q1.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.print(s);
                try {
//                    向q2中放入一个内容
                    q2.put("1");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println();
        }).start();
    }

    /**
     * 多线程拼接字符串
     * 使用两个线程将1到26和A到Z依次拼接到一起
     * 管道流实现
     */
    public void getMultiThreadStringArrJoin_Piped() throws IOException {
        PipedInputStream inputStream = new PipedInputStream();
        PipedInputStream inputStream1 = new PipedInputStream();
        PipedOutputStream outputStream = new PipedOutputStream();
        PipedOutputStream outputStream1 = new PipedOutputStream();
        inputStream.connect(outputStream1);
        inputStream1.connect(outputStream);
        String msg = "1";
        new Thread(() -> {
            byte[] bytes = new byte[1];
            try {
                for (String s : str1) {
                    inputStream.read(bytes);
                    System.out.print(s);
                    outputStream.write(msg.getBytes());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(() -> {
            try {
                byte[] bytes = new byte[1];
                for (String s : str2) {
                        System.out.print(s);
                    outputStream1.write(msg.getBytes());
                    inputStream1.read(bytes);
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }
    CountDownLatch countDownLatch = new CountDownLatch(1);
    /**
     * 多线程拼接字符串
     * 使用两个线程将1到26和A到Z依次拼接到一起
     * 管道流实现
     */
    public void getMultiThreadStringArrJoin_WaitNotify(){
        final Object o = new Object();
        new Thread(()->{
            synchronized (o){
                try {
                    countDownLatch.await();
                    for (String s : str1){
                        System.out.print(s);
//                        叫醒另外一个线程
                        o.notify();
//                        让出锁
                        o.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
//                必须释放否则无法停止程序
                o.notify();
            }
        }).start();
        new Thread(()->{
            synchronized (o){
                try {
                    for (String s : str2){
                        System.out.print(s);
                        countDownLatch.countDown();
                        o.notify();
                        o.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                o.notify();
            }
        }).start();
    }
    static int m = 0;
    Object o = new Object();
    public void multiThread() throws InterruptedException {
        Thread [] ts = new Thread[100];
        for (int i = 0; i < 100; i++) {
            Thread t = new Thread(()->{
                for (int j = 0; j < 100; j++) {
                    synchronized (o){
                        m++;
                    }
                }
            });
            ts[i]=t;
        }

        for (Thread t : ts) {
            t.start();
        }
        for (Thread t : ts) {
            t.join();
        }
        System.out.println(m);
    }

    public void multiThreadFuture(){
        Callable<String> c = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return "hello";
            }
        };
        ExecutorService executorService = Executors.newCachedThreadPool();
        Future<String> future = executorService.submit(c);
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }

    public void multiThreadListenableFuture(){
//        谷歌的guava工具包 关于future的实现类,可以进行监听future的返回值
        ListeningExecutorService service
//        添加了装饰器,支持可以监听事件
                = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
        ListenableFuture<String> future = service.submit(()->{
           return "wangxing";
        });
        Futures.addCallback(future, new FutureCallback<String>() {
            @Override
            public void onSuccess(@Nullable String s) {
                System.out.println(s);
            }

            @Override
            public void onFailure(Throwable throwable) {
                throwable.printStackTrace();
            }
        },service);
        service.shutdown();

    }
    public void multiThreadFutures(){
//        CompletableFuture<String> future = CompletableFuture.supplyAsync(()->);
    }
}
